package org.luxor.cloud.authentication.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import org.luxor.commons.core.utils.StrKit;
import org.luxor.commons.core.utils.StringUtils;
import org.luxor.commons.core.web.RestStatus;
import org.luxor.commons.core.web.controller.BaseRestController;
import org.luxor.commons.core.web.data.R;
import org.luxor.commons.security.utils.SecurityUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import springfox.documentation.annotations.ApiIgnore;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.Principal;
import java.util.Map;

/**
 * 系统身份认证
 *
 * @author Mark @date 2020-07-26 14:21:10
 */

/**
 * 系统身份认证
 *
 * @author Mark @date 2020-07-26 14:21:10
 */
@Controller
@Api(tags = "系统身份认证")
public class AuthTokenController extends BaseRestController {

    @Resource
    private TokenStore tokenStore;
    @Resource
    private ClientDetailsService clientDetailsService;

    @ApiIgnore
    @GetMapping("/login")
    @ApiOperation(value = "账号登陆页")
    public ModelAndView require( ModelAndView modelAndView, @RequestParam(required = false) String error) {
        modelAndView.setViewName("login");
        modelAndView.addObject("error", error);
        return modelAndView;
    }

    @ApiIgnore
    @GetMapping("/confirm_access")
    @ApiOperation(value = "确认授权页面", hidden = true)
    public ModelAndView confirm(ModelAndView modelAndView,
                                HttpServletRequest request,
                                HttpSession session) {
        Map<String, Object> scopeList = (Map<String, Object>) request.getAttribute("scopes");
        modelAndView.addObject("scopeList", scopeList.keySet());

        Object auth = session.getAttribute("authorizationRequest");
        if (auth != null) {
            AuthorizationRequest authorizationRequest = (AuthorizationRequest) auth;
            ClientDetails clientDetails = clientDetailsService.loadClientByClientId(authorizationRequest.getClientId());
            modelAndView.addObject("app", clientDetails.getAdditionalInformation());
            modelAndView.addObject("user", SecurityUtils.getUser());
        }

        modelAndView.setViewName("confirm");
        return modelAndView;
    }


    @GetMapping("/token/user_info")
    @ApiOperation("Token解析")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "身份凭证(token)", paramType = "header", required = true)
    public ResponseEntity<Principal> user(@RequestHeader(value = HttpHeaders.AUTHORIZATION) String authHeader) {
        // 获取授权凭证
        String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrKit.EMPTY).trim();
        OAuth2AccessToken token = tokenStore.readAccessToken(tokenValue);
        if (token == null || StringUtils.isBlank(token.getValue())) {
            return getSuccess(R.failed(RestStatus.TOKEN_INVALID));
        }

        // 获取身份信息
        OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(token);
        if (token == null) {
            return getSuccess(R.failed(RestStatus.TOKEN_INVALID));
        }
        return getSuccess(R.ok(auth2Authentication.getPrincipal()));
    }

    @DeleteMapping("/token/removeToken")
    @ApiOperation("移除Token")
    @ApiImplicitParam(name = HttpHeaders.AUTHORIZATION, value = "身份凭证(token)", paramType = "header", required = true)
    public ResponseEntity removeToken(@RequestHeader(value = HttpHeaders.AUTHORIZATION) String authHeader) {
        String tokenValue = authHeader.replace(OAuth2AccessToken.BEARER_TYPE, StrKit.EMPTY).trim();
        removeAccessToken(tokenValue);
        return getSuccess(R.ok("移除成功 bye"));
    }

    private void removeAccessToken(String tokenValue) {
        OAuth2AccessToken token = tokenStore.readAccessToken(tokenValue);
        if (token != null && StringUtils.isNotBlank(token.getValue())) {
            // 清空access token
            tokenStore.removeAccessToken(token);

            OAuth2RefreshToken refreshToken = token.getRefreshToken();
            if (refreshToken != null && StringUtils.isNotBlank(refreshToken.getValue())) {
                // 清空 refresh token
                tokenStore.removeRefreshToken(refreshToken);
            }
        }
    }

}

